home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The 640 MEG Shareware Studio 2
/
The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO
/
clang
/
nn.zip
/
KILL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-12-31
|
16KB
|
762 lines
#include "config.h"
#include "term.h"
#include "regexp.h"
/*
* kill file handling
*/
export int killed_articles;
char KILL_FILE[] = "kill";
char COMPILED_KILL[] = "KILL.COMP";
extern char *quick_match();
#define COMP_KILL_MAGIC 0x4b694c6d /* KiLm */
/*
* kill flags
*/
#define COMP_KILL_ENTRY 0x80
#define AUTO_KILL 0x01
#define AUTO_SELECT 0x00 /* pseudo flag */
#define ON_SUBJECT 0x02
#define ON_SENDER 0x00 /* pseudo flag */
#define KILL_MUST_MATCH 0x10
#define KILL_ON_REGEXP 0x20
/*
* external flag representation
*/
#define EXT_AUTO_KILL '!'
#define EXT_AUTO_SELECT '+'
#define EXT_ON_SUBJECT 's'
#define EXT_ON_SENDER 'n'
#define EXT_KILL_MUST_MATCH '='
#define EXT_KILL_ON_REGEXP '/'
/*
* period = nnn DAYS
*/
#define DAYS * 24 * 60 * 60
/*
* kill_article
*
* return 1 to kill article, 0 to include it
*/
typedef struct kill_list_entry {
int kill_flag;
char *kill_pattern;
regexp *kill_regexp;
struct kill_list_entry *next_kill;
} kill_list_entry;
static kill_list_entry *kill_tab;
static char *kill_patterns;
static kill_list_entry dummy_kill = {
0, (char *)NULL, (regexp *)NULL, (kill_list_entry *)NULL
};
static kill_list_entry *global_kill_list = &dummy_kill;
static kill_list_entry *end_kill_list = &dummy_kill;
static kill_list_entry latest_kl_entry;
kill_article(ah)
article_header *ah;
{
register kill_list_entry *kl;
char *string;
end_kill_list->next_kill = (kill_list_entry *)(current_group->kill_list);
kl = global_kill_list;
while (kl = kl->next_kill) {
if (kl->kill_flag & ON_SUBJECT)
string = ah->subject;
else
string = ah->sender;
if (kl->kill_flag & KILL_MUST_MATCH) {
if (strcmp(kl->kill_pattern, string))
continue;
} else
if (kl->kill_flag & KILL_ON_REGEXP) {
if (regexec(kl->kill_regexp, string) == 0)
continue;
} else
if (quick_match(string, kl->kill_pattern) == NULL)
continue;
if (kl->kill_flag & AUTO_KILL) {
killed_articles++;
return 1;
}
ah->flag |= A_SELECT | A_AUTO;
break;
}
return 0;
}
auto_select_article(ah, do_select)
article_header *ah;
int do_select;
{
register kill_list_entry *kl;
kill_list_entry kl_head;
char *string;
if (do_select == 2) {
kl = &kl_head;
kl->next_kill = &latest_kl_entry;
} else {
end_kill_list->next_kill = ah->a_group ?
(kill_list_entry *)(ah->a_group->kill_list) :
(kill_list_entry *)(current_group->kill_list);
kl = global_kill_list;
}
while (kl = kl->next_kill) {
if (do_select) {
if (kl->kill_flag & AUTO_KILL) continue;
} else {
if ((kl->kill_flag & AUTO_KILL) == 0) continue;
}
check_one:
if (kl->kill_flag & ON_SUBJECT)
string = ah->subject;
else
string = ah->sender;
if (kl->kill_flag & KILL_MUST_MATCH) {
if (strcmp(kl->kill_pattern, string))
continue;
} else
if (kl->kill_flag & KILL_ON_REGEXP) {
if (regexec(kl->kill_regexp, string) == 0)
continue;
} else
if (quick_match(string, kl->kill_pattern) == NULL)
continue;
killed_articles++;
return 1;
}
return 0;
}
enter_kill_file(gh, pattern, flag, days)
group_header *gh;
char *pattern;
int flag;
int days;
{
time_t now;
FILE *killf;
register kill_list_entry *kl;
regexp *re;
char *str;
str = copy_str(pattern);
if (flag & KILL_ON_REGEXP) {
re = regcomp(pattern);
if (re == NULL) return;
} else {
re = NULL;
if ((flag & KILL_MUST_MATCH) == 0)
init_quick_match(str);
}
killf = open_file(relative(nn_directory, "kill"), OPEN_APPEND);
if (killf == NULL) {
msg("cannot create kill file");
return;
}
if (days >= 0) {
time(&now);
if (days == 0) days = 30;
fprintf(killf, "%lu:", (long)(now + days DAYS));
}
if (gh) fputs(gh->group_name, killf);
fputc(':', killf);
fputc(flag & AUTO_KILL ? EXT_AUTO_KILL : EXT_AUTO_SELECT, killf);
fputc(flag & ON_SUBJECT ? EXT_ON_SUBJECT : EXT_ON_SENDER, killf);
if (flag & KILL_MUST_MATCH) fputc(EXT_KILL_MUST_MATCH, killf);
if (flag & KILL_ON_REGEXP) fputc(EXT_KILL_ON_REGEXP, killf);
fputc(':', killf);
fputs(pattern, killf);
fputc(NL, killf);
fclose(killf);
rm_kill_file();
kl = (kill_list_entry *)calloc(1, sizeof(kill_list_entry));
mem_check((char *)kl, 1, "kill list entry");
latest_kl_entry.kill_pattern = kl->kill_pattern = str;
latest_kl_entry.kill_regexp = kl->kill_regexp = re;
latest_kl_entry.kill_flag = kl->kill_flag = flag;
latest_kl_entry.next_kill = NULL;
if (gh) {
kl->next_kill = (kill_list_entry *)(gh->kill_list);
gh->kill_list = (char *)kl;
} else {
kl->next_kill = NULL;
end_kill_list->next_kill = kl;
end_kill_list = kl;
}
}
typedef struct {
group_number ck_group;
char ck_flag;
long ck_pattern_index;
} comp_kill_entry;
typedef struct {
long ckh_magic;
off_t ckh_pattern_offset;
long ckh_pattern_size;
long ckh_entries;
} comp_kill_header;
kill_menu(ah)
article_header *ah;
{
int flag, days;
char *mode1, *mode2;
char *pattern, *dflt, *days_str, buffer[512];
extern article_header *get_menu_article();
group_header *gh;
prompt("\1AUTO\1 (K)ill or (S)elect (CR => Kill subject 1 month) ");
switch (get_c()) {
case CR:
case NL:
if (ah == NULL) {
ah = get_menu_article();
if (ah == NULL) return -1;
}
strcpy(buffer, ah->subject);
enter_kill_file(current_group, buffer,
AUTO_KILL | ON_SUBJECT | KILL_MUST_MATCH, 30);
msg("DONE");
return 1;
case 'k':
case 'K':
case '!':
flag = AUTO_KILL;
mode1 = "KILL";
break;
case 's':
case 'S':
case '+':
flag = AUTO_SELECT;
mode1 = "SELECT";
break;
default:
return -1;
}
prompt("\1AUTO %s\1 on (S)ubject or (N)ame ?", mode1);
dflt = NULL;
switch (get_c()) {
case 'n':
case 'N':
flag |= ON_SENDER;
if (ah) dflt = ah->sender;
mode2 = "Name";
break;
case 's':
case 'S':
case SP:
case CR:
case NL:
flag |= ON_SUBJECT;
if (ah) dflt = ah->subject;
mode2 = "Subject";
break;
default:
return -1;
}
prompt("\1%s %s:\1", mode1, mode2);
pattern = get_s(dflt, NONE, "%=/", NO_COMPLETION);
if (pattern == NULL) return -1;
if (*pattern == NUL || *pattern == '%' || *pattern == '=') {
if (dflt && *dflt)
pattern = dflt;
else {
if ((ah = get_menu_article()) == NULL) return -1;
pattern = (flag & ON_SUBJECT) ? ah->subject : ah->sender;
}
flag |= KILL_MUST_MATCH;
} else
if (*pattern == '/') {
prompt("\1%s %s\1 (regexp): ", mode1, mode2);
pattern = get_s(NONE, NONE, NONE, NO_COMPLETION);
if (pattern == NULL || *pattern == NUL) return -1;
flag |= KILL_ON_REGEXP;
}
strcpy(buffer, pattern);
pattern = buffer;
prompt("\1%s\1 in (G)roup '%s' or in (A)ll groups",
mode1, current_group->group_name);
switch (get_c()) {
case 'g':
case 'G':
case SP:
case CR:
case NL:
gh = current_group;
break;
case 'A':
case 'a':
gh = NULL;
break;
default:
return -1;
}
prompt("\1Lifetime of entry in days\1 (P)ermanent ");
days_str = get_s(" 30 days", NONE, "pP", NO_COMPLETION);
if (days_str == NULL) return -1;
if (*days_str == NUL) {
days_str = "30 days";
days = 30;
} else if (*days_str == 'p' || *days_str == 'P') {
days_str = "perm";
days = -1;
} else if (isdigit(*days_str)) {
days = atoi(days_str);
sprintf(days_str, "%d days", days);
} else {
ding();
return -1;
}
prompt("\1CONFIRM\1 %s %s %s%s: %-.35s%s ",
mode1, mode2, days_str,
(flag & KILL_MUST_MATCH) ? " exact" :
(flag & KILL_ON_REGEXP) ? " regexp" : "",
pattern, strlen(pattern) > 35 ? "..." : "");
if (yes(0) <= 0) return -1;
enter_kill_file(gh, pattern, flag, days);
return (flag & AUTO_KILL) ? 1 : 0;
}
init_kill()
{
FILE *killf;
comp_kill_header header;
comp_kill_entry entry;
register group_header *gh;
register kill_list_entry *kl;
time_t kill_age, comp_age;
register long n;
int first_try = 1;
import char *delayed_msg;
Loop_Groups_Header(gh)
gh->kill_list = NULL;
kill_age = file_exist(relative(nn_directory, KILL_FILE), "frw");
if (kill_age == 0) return 0;
comp_age = file_exist(relative(nn_directory, COMPILED_KILL), "fr");
again:
if (comp_age < kill_age && !compile_kill_file()) return 0;
kill_tab = NULL;
kill_patterns = NULL;
killf = open_file(relative(nn_directory, COMPILED_KILL), OPEN_READ);
if (killf == NULL) return 0;
if (fread((char *)&header, sizeof(header), 1, killf) != 1) goto err;
if (header.ckh_magic != COMP_KILL_MAGIC) goto err;
kill_patterns = malloc((unsigned)header.ckh_pattern_size);
mem_check(kill_patterns, (int)header.ckh_pattern_size, "kill bytes");
kill_tab = (kill_list_entry *)
calloc((unsigned)header.ckh_entries, sizeof(kill_list_entry));
mem_check((char *)kill_tab, (int)header.ckh_entries, "kill entries");
fseek(killf, (off_t)(header.ckh_entries * sizeof(entry)), 1);
if (fread(kill_patterns, sizeof(char), (int)header.ckh_pattern_size, killf)
!= header.ckh_pattern_size) goto err;
fseek(killf, (off_t)sizeof(header), 0);
for (n = header.ckh_entries, kl = kill_tab; --n >= 0; kl++) {
if (fread((char *)&entry, sizeof(entry), 1, killf) != 1) goto err;
if (header.ckh_pattern_size <= entry.ck_pattern_index ||
entry.ck_pattern_index < 0) goto err;
kl->kill_pattern = kill_patterns + entry.ck_pattern_index;
kl->kill_flag = entry.ck_flag;
if (kl->kill_flag & KILL_ON_REGEXP)
kl->kill_regexp = regcomp(kl->kill_pattern);
else
kl->kill_regexp = NULL;
if (entry.ck_group >= 0) {
gh = active_groups + entry.ck_group;
kl->next_kill = (kill_list_entry *)(gh->kill_list);
gh->kill_list = (char *)kl;
} else {
kl->next_kill = NULL;
end_kill_list->next_kill = kl;
end_kill_list = kl;
}
}
fclose(killf);
return 1;
err:
if (kill_patterns != NULL) free(kill_patterns);
if (kill_tab != NULL) free(kill_tab);
fclose(killf);
rm_kill_file();
if (first_try) {
first_try = 0;
comp_age = 0;
goto again;
}
delayed_msg = "Error in compiled kill file (ignored)";
Loop_Groups_Header(gh)
gh->kill_list = NULL;
end_kill_list = global_kill_list = &dummy_kill;
return 0;
}
static compile_kill_file()
{
FILE *killf, *compf, *patternf, *dropf;
comp_kill_header header;
comp_kill_entry entry;
time_t now, age;
off_t cur_line_start;
char line[512];
register char *cp, *np;
register int c;
group_header *gh;
int flag, any_errors;
extern char *temp_file;
any_errors = 0;
header.ckh_entries = 0;
killf = open_file(relative(nn_directory, KILL_FILE),
OPEN_READ | DONT_CREATE);
if (killf == NULL) return 0;
compf = open_file(relative(nn_directory, COMPILED_KILL), OPEN_CREATE);
if (compf == NULL) goto err1;
new_temp_file();
if ((patternf = open_file(temp_file, OPEN_CREATE)) == NULL)
goto err2;
dropf = NULL;
printf("\nCompiling kill file\n");
fseek(compf, (off_t)sizeof(header), 0);
time(&now);
next_entry:
for (;;) {
cur_line_start = ftell(killf);
if (fgets(line, 512, killf) == NULL) break;
cp = line;
while (*cp && isascii(*cp) && isspace(*cp)) cp++;
if (*cp == NUL || *cp == '#' || !isascii(*cp)) continue;
if ((np = strchr(cp, ':')) == NULL) goto bad_entry;
/* optional "age:" */
if (np != cp && isdigit(*cp)) {
*np++ = NUL;
age = (time_t)atol(cp);
if (age < now) goto drop_entry;
cp = np;
if ((np = strchr(cp, ':')) == NULL) goto bad_entry;
}
/* "group-name:" or ":" for all groups */
if (np == cp) {
entry.ck_group = -1;
np++;
} else {
*np++ = NUL;
if ((gh = lookup(cp)) == NULL) {
printf("Unknown group in kill file: %s\n", cp);
any_errors++;
goto drop_entry;
}
entry.ck_group = gh->group_num;
}
/* flags */
cp = np;
flag = COMP_KILL_ENTRY;
for (;;) {
switch (*cp++) {
case EXT_AUTO_KILL:
flag |= AUTO_KILL;
continue;
case EXT_AUTO_SELECT:
flag |= AUTO_SELECT;
continue;
case EXT_ON_SUBJECT:
flag |= ON_SUBJECT;
continue;
case EXT_ON_SENDER:
flag |= ON_SENDER;
continue;
case EXT_KILL_MUST_MATCH:
flag |= KILL_MUST_MATCH;
continue;
case EXT_KILL_ON_REGEXP:
flag |= KILL_ON_REGEXP;
continue;
case ':':
break;
case NL:
goto bad_entry;
default:
printf("Ignored flag '%c' in kill file\n", cp[-1]);
any_errors++;
continue;
}
break;
}
entry.ck_flag = flag;
if ((np = strchr(cp, NL)) == NULL) goto bad_entry;
*np++ = NUL;
if ((flag & (KILL_MUST_MATCH | KILL_ON_REGEXP)) == 0)
init_quick_match(cp);
entry.ck_pattern_index = ftell(patternf);
if (fwrite(&entry, sizeof(entry), 1, compf) != 1)
goto err3;
if (fwrite(cp, sizeof(char), np - cp, patternf) != (np - cp))
goto err3;
header.ckh_entries++;
}
header.ckh_pattern_size = ftell(patternf);
fclose(patternf);
patternf = open_file(temp_file, OPEN_READ | OPEN_UNLINK);
if (patternf == NULL) goto err2;
header.ckh_pattern_offset = ftell(compf);
while ((c = getc(patternf)) != EOF)
putc(c, compf);
fclose(patternf);
rewind(compf);
header.ckh_magic = COMP_KILL_MAGIC;
if (fwrite((char *)&header, sizeof(header), 1, compf) != 1)
goto err2;
fclose(compf);
fclose(killf);
if (dropf != NULL) fclose(dropf);
if (any_errors) {
putchar(NL);
any_key(0);
}
return 1;
bad_entry:
printf("Incomplete kill file entry:\n%s", line);
fl;
any_errors++;
drop_entry:
if (dropf == NULL) {
dropf = open_file(relative(nn_directory, KILL_FILE),
OPEN_UPDATE | DONT_CREATE);
if (dropf == NULL) goto next_entry;
}
fseek(dropf, cur_line_start, 0);
fwrite("# ", sizeof(char), 2, dropf);
goto next_entry;
err3:
fclose(patternf);
unlink(temp_file);
err2:
fclose(compf);
rm_kill_file();
err1:
fclose(killf);
if (dropf != NULL) fclose(dropf);
msg("cannot compile kill file");
return 0;
}
rm_kill_file()
{
unlink(relative(nn_directory, COMPILED_KILL));
}
free_kill_entries()
{
register group_header *gh;
Loop_Groups_Header(gh)
if (gh->kill_list) {
free_kill_list((kill_list_entry *)(gh->kill_list));
gh->kill_list = NULL;
}
end_kill_list->next_kill = NULL;
free_kill_list(global_kill_list->next_kill);
end_kill_list = global_kill_list = &dummy_kill;
if (kill_patterns != NULL) free(kill_patterns);
if (kill_tab != NULL) free(kill_tab);
}
static free_kill_list(kl)
register kill_list_entry *kl;
{
register kill_list_entry *nxt;
while (kl) {
nxt = kl->next_kill;
if (kl->kill_regexp != NULL) free(kl->kill_regexp);
if ((kl->kill_flag & COMP_KILL_ENTRY) == 0) {
if (kl->kill_pattern != NULL) free(kl->kill_pattern);
free(kl);
}
kl = nxt;
}
}
dump_kill_list()
{
register kill_list_entry *kl;
pg_init(0, 1);
pg_next();
so_printf("\1GLOBAL kill list entries:\1");
kl = end_kill_list->next_kill = NULL;
kl = global_kill_list;
while (kl = kl->next_kill)
if (print_kill(kl) < 0) goto out;
if (pg_next() < 0) goto out;
if (pg_next() < 0) goto out;
kl = (kill_list_entry *)(current_group->kill_list);
if (kl == NULL) {
printf("No kill entries for %s", current_group->group_name);
goto out;
}
so_printf("\1GROUP %s kill list entries\1", current_group->group_name);
while (kl) {
if (print_kill(kl) < 0) break;
kl = kl->next_kill;
}
out:
pg_end();
}
print_kill(kl)
register kill_list_entry *kl;
{
if (pg_next() < 0) return -1;
printf("\r%s ON %s '%.35s'%s\n",
kl->kill_flag & AUTO_KILL ? "KILL" : "SELECT",
kl->kill_flag & ON_SUBJECT ? "SUBJECT" : "NAME",
kl->kill_pattern,
kl->kill_flag & KILL_MUST_MATCH ? " (exact)" :
kl->kill_flag & KILL_ON_REGEXP ? " (re)" : "");
return 0;
}